/**
 * Copyright (c) 2012, Brent Mucci, Ken Anderson
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **/

#include "mcl_visualizer.h"
#include <iostream>
#include <algorithm>

// Using SFML to display large bitmap images is really slow.
// The preferred method is to use OpenGL directly instead.
#define USE_OPENGL

// Windows has a flipped coordinate system.
#if defined _WIN32 || defined _WIN64
#define FLIP_IMAGE
#endif

// Location of the true-type font to display in the window.
static const char* FONT_FILENAME = ".." DDEL ".." DDEL "media-cl" DDEL "fonts" DDEL "Achafexp.ttf";

using namespace mcl;

Visualizer::Visualizer(int windowWidth, int windowHeight, int windowCells)
#ifdef USE_SFML
	: m_cellWidth(windowWidth/windowCells),
	  m_cellHeight(windowHeight/windowCells),
	  m_windowCells(windowCells),
	  m_zoomFactor(1.0f),
	  m_sfImage(m_cellWidth, m_cellHeight)
{
	m_app.Create(sf::VideoMode(windowWidth, windowHeight, 32), "OpenCL VS CPU Demo"),
	m_sprite.SetImage(m_sfImage);
	m_app.SetFramerateLimit(30);
	m_infoFont.LoadFromFile(FONT_FILENAME);
	m_infoText.SetFont(m_infoFont);
	m_infoText.SetColor(sf::Color(200,200,200));
	m_infoText.SetSize(20);
	m_infoText.SetStyle(sf::String::Bold);
	m_infoText.Move(0.f,0.f);
	m_app.UseVerticalSync(false);

#ifdef USE_OPENGL
	m_app.SetActive();

	glClearColor(0.f, 0.f, 0.f, 0.f);
	glShadeModel(GL_FLAT);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);

	glViewport(0, 0, (GLsizei) windowWidth, (GLsizei) windowHeight);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0.0, (GLdouble) windowWidth, 0.0, (GLdouble) windowHeight);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
#endif
}
#else
{ }
#endif

Visualizer::~Visualizer()
{
}

bool Visualizer::isOpened() 
{ 
#ifdef USE_SFML
	return m_app.IsOpened();
#endif
	return true;
}

void Visualizer::drawImage( const Image &image, int cellColumn, int cellRow )
{
#ifdef USE_SFML
#ifdef USE_OPENGL
	m_app.SetActive();

	const int xOffset = cellColumn*m_cellWidth;
	const int yOffset = cellRow*m_cellHeight;
	
#ifdef FLIP_IMAGE
	// Flip image
	glPixelZoom (m_zoomFactor, -m_zoomFactor);
	// Set location
	glRasterPos2i(xOffset,m_cellHeight+yOffset);
#else
	glPixelZoom (m_zoomFactor, m_zoomFactor);
	// Set location
	glRasterPos2i(xOffset,yOffset);
#endif

	// Draw pixels
	const GLubyte * gldata = (const GLubyte *) image.data();
	glDrawPixels(m_cellWidth, m_cellHeight, GL_RGBA, 
							GL_UNSIGNED_BYTE, gldata);
	//glFlush();
#else
	m_sfImage.LoadFromPixels(m_cellWidth, m_cellHeight, (const sf::Uint8 *)image.data());
	m_sprite.SetPosition(floor((float)cellColumn * m_cellWidth), floor((float)cellRow * m_cellHeight));
	m_app.Draw(m_sprite);
#endif
#endif
}

void Visualizer::print(const std::string & text)
{
	std::cout << text << std::endl;
#ifdef USE_SFML
	m_infoText.SetText(text);
#endif
}

void Visualizer::clear()
{
#ifdef USE_OPENGL
	glClear(GL_COLOR_BUFFER_BIT);
#endif
#ifdef USE_SFML
	m_app.Clear();
#endif
}

void Visualizer::display()
{
#ifdef USE_SFML
#ifndef USE_OPENGL
	m_app.Draw(m_infoText);
#endif
	m_app.Display();
#endif
}

// pass in variable references as necessary
void Visualizer::handleEvents()
{
#ifdef USE_SFML
	while (m_app.GetEvent(m_event))
	{
		if (m_event.Type == sf::Event::Closed)
		{
			m_app.Close();
		}
		else if(m_event.Type == sf::Event::KeyPressed)
		{
			if(m_event.Key.Code == sf::Key::Escape){
				m_app.Close();
			}
		}
	}
#endif
}
